package cn.iocoder.yudao.module.system.dal.mysql.useractivity;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.dal.dataobject.useractivity.UserActivityStatsDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDate;
import java.util.List;

/**
 * 用户活跃度统计 Mapper
 *
 * @author 系统开发团队
 */
@Mapper
public interface UserActivityStatsMapper extends BaseMapperX<UserActivityStatsDO> {

    /**
     * 根据统计日期和类型查询
     */
    default UserActivityStatsDO selectByDateAndType(LocalDate statDate, Integer statType) {
        return selectOne(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getStatDate, statDate)
                .eq(UserActivityStatsDO::getStatType, statType));
    }

    /**
     * 查询指定日期范围和类型的统计数据
     */
    default List<UserActivityStatsDO> selectByDateRangeAndType(LocalDate startDate, LocalDate endDate, Integer statType) {
        return selectList(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED)
                .orderByDesc(UserActivityStatsDO::getStatDate));
    }

    /**
     * 查询待计算的记录
     */
    default List<UserActivityStatsDO> selectPendingCalculation() {
        return selectList(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_PENDING)
                .orderByAsc(UserActivityStatsDO::getStatDate));
    }

    /**
     * 查询指定日期的待计算记录
     */
    default List<UserActivityStatsDO> selectPendingCalculationByDate(LocalDate statDate) {
        return selectList(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getStatDate, statDate)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_PENDING)
                .orderByAsc(UserActivityStatsDO::getStatType));
    }

    /**
     * 查询最新的统计数据
     */
    default List<UserActivityStatsDO> selectLatestStats(Integer statType, Integer limit) {
        return selectList(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED)
                .orderByDesc(UserActivityStatsDO::getStatDate)
                .last("LIMIT " + limit));
    }

    /**
     * 统计指定日期范围内的平均活跃用户数
     */
    default Long selectAvgActiveUsers(LocalDate startDate, LocalDate endDate, Integer statType) {
        LambdaQueryWrapperX<UserActivityStatsDO> queryWrapper = new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED);
        
        queryWrapper.select(UserActivityStatsDO::getActiveUsers);
        
        LambdaQueryWrapperX<UserActivityStatsDO> countWrapper = new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED);
        
        List<Object> results = selectObjs(queryWrapper);
        Long count = selectCount(countWrapper);
        
        if (count == 0) {
            return 0L;
        }
        
        long sum = results.stream()
                .mapToLong(obj -> (Long) obj)
                .sum();
        
        return sum / count;
    }

    /**
     * 查询活跃度趋势数据
     */
    default List<UserActivityStatsDO> selectActivityTrend(LocalDate startDate, LocalDate endDate, Integer statType) {
        return selectList(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED)
                .orderByAsc(UserActivityStatsDO::getStatDate));
    }

    /**
     * 统计计算状态数量
     */
    default long countByCalculationStatus(Integer calculationStatus) {
        return selectCount(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getCalculationStatus, calculationStatus));
    }

    /**
     * 统计指定日期的记录数量
     */
    default long countByDate(LocalDate statDate) {
        return selectCount(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getStatDate, statDate));
    }

    /**
     * 统计指定日期已完成计算的记录数量
     */
    default long countCompletedByDate(LocalDate statDate) {
        return selectCount(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .eq(UserActivityStatsDO::getStatDate, statDate)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED));
    }

    /**
     * 删除过期数据
     */
    default int deleteExpiredData(LocalDate beforeDate) {
        return delete(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .lt(UserActivityStatsDO::getStatDate, beforeDate));
    }

    /**
     * 查询指定时间段内的峰值数据
     */
    default UserActivityStatsDO selectPeakActivity(LocalDate startDate, LocalDate endDate, Integer statType) {
        return selectOne(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED)
                .orderByDesc(UserActivityStatsDO::getActiveUsers)
                .last("LIMIT 1"));
    }

    /**
     * 查询指定时间段内的低谷数据
     */
    default UserActivityStatsDO selectLowestActivity(LocalDate startDate, LocalDate endDate, Integer statType) {
        return selectOne(new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eq(UserActivityStatsDO::getCalculationStatus, UserActivityStatsDO.CALCULATION_STATUS_COMPLETED)
                .orderByAsc(UserActivityStatsDO::getActiveUsers)
                .last("LIMIT 1"));
    }

    /**
     * 分页查询统计数据
     */
    default PageResult<UserActivityStatsDO> selectPage(LocalDate startDate, LocalDate endDate, 
                                                       Integer statType, Integer calculationStatus,
                                                       int pageNo, int pageSize) {
        PageParam pageParam = new PageParam();
        pageParam.setPageNo(pageNo);
        pageParam.setPageSize(pageSize);
        return selectPage(pageParam, new LambdaQueryWrapperX<UserActivityStatsDO>()
                .betweenIfPresent(UserActivityStatsDO::getStatDate, startDate, endDate)
                .eqIfPresent(UserActivityStatsDO::getStatType, statType)
                .eqIfPresent(UserActivityStatsDO::getCalculationStatus, calculationStatus)
                .orderByDesc(UserActivityStatsDO::getStatDate));
    }

    /**
     * 插入或更新统计数据
     */
    default void insertOrUpdateStats(UserActivityStatsDO stats) {
        UserActivityStatsDO existing = selectByDateAndType(stats.getStatDate(), stats.getStatType());
        if (existing != null) {
            stats.setId(existing.getId());
            updateById(stats);
        } else {
            insert(stats);
        }
    }
}